package com.shycloud.mido.common.security.component;

import cn.hutool.http.HttpStatus;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shycloud.mido.common.core.constant.CommonConstants;
import com.shycloud.mido.common.core.util.R;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.xmlbeans.impl.common.InvalidLexicalValueException;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 * 客户端异常处理
 *
 * @author nianhua.jiang
 * @date 2020/07/24
 * 1. 可以根据 AuthenticationException 不同细化异常处理
 */
@Slf4j
@Component
@AllArgsConstructor
public class ResourceAuthExceptionEntryPoint implements AuthenticationEntryPoint {


	/** 用于传输json到移动端的对象 */
	private final ObjectMapper objectMapper;

	/** 固定文字：token错误信息 - Full authentication is required to access this resource */
	public static final String NON_TOKEN = "Full authentication is required to access this resource";
	/** token过期时的错误信息：登录信息已过期，请重新登录 */
	public static final String MSG_EXPIRED_TOKEN = "您的账号在其他设备上登录，如非本人操作，请及时修改密码";
	/** 没有token时的错误信息：请先登录 */
	public static final String MSG_NOT_TOKEN = "请先登录";

	@Override
	@SneakyThrows
	public void commence(HttpServletRequest request, HttpServletResponse response,
						 AuthenticationException authException) {

		//设置字符集
		response.setCharacterEncoding(CommonConstants.UTF8);
		//设置内容类型 - "application/json;charset=UTF-8"
		response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
		//定义统一的返回格式
		R<String> result = new R<>();
		//设置 code = 1 代表错误码
		result.setCode(CommonConstants.FAIL);
		//如果是 InvalidTokenException 异常，则为token失效的情况，给出错误的提示信息
		if (authException.getCause() instanceof InvalidTokenException) {
			//定义特殊错误码 = 2，这个与前端商量好的自定义 code 码，修正请与移动端确认
			result.setCode(2);
			result.setMsg(MSG_EXPIRED_TOKEN);
			result.setData(authException.getMessage());
		}
		//其他异常
		else if (authException != null) {
			result.setMsg(authException.getMessage());
			result.setData(authException.getMessage());
			//TODO 没有token的场合，自定义提示信息 注：这个目前来说没有好的解决办法，这能这么写死判断(以后会重构下)
			if (NON_TOKEN.equals(authException.getMessage())) {
				//返回的提示信息
				result.setMsg(MSG_NOT_TOKEN);
				result.setData(authException.getMessage());
			}

			if (authException.getMessage().startsWith("wx_not_bind")) {
				//返回的提示信息
				result.setCode(3);
				result.setMsg("请先绑定手机号");
				result.setData(authException.getMessage().split(",")[1]);
			}
		}
		//http 状态码 401
		response.setStatus(HttpStatus.HTTP_UNAUTHORIZED);
		PrintWriter printWriter = response.getWriter();
		printWriter.append(objectMapper.writeValueAsString(result));
	}
}
